"""
提示词模板管理模块
提供提示词模板的加载和占位符替换功能
"""
from pathlib import Path
from typing import Dict, Any, Optional
from loguru import logger
import re


class PromptTemplateLoader:
    """提示词模板加载器"""
    
    def __init__(self, prompts_dir: str = "./prompts", prompt_set: str = "default"):
        """
        初始化加载器
        
        Args:
            prompts_dir: 提示词目录
            prompt_set: 提示词集名称
        """
        self.prompts_dir = Path(prompts_dir)
        self.prompt_set = prompt_set
        self.template_cache: Dict[str, str] = {}
    
    def load_template(self, role: str) -> str:
        """
        加载角色提示词模板
        
        Args:
            role: 角色名称（planner/outliner/character_designer/scriptwriter/editor）
            
        Returns:
            提示词模板字符串
            
        Raises:
            FileNotFoundError: 模板文件不存在
        """
        # 检查缓存
        cache_key = f"{self.prompt_set}/{role}"
        if cache_key in self.template_cache:
            return self.template_cache[cache_key]
        
        # 加载模板文件
        template_path = self.prompts_dir / self.prompt_set / f"{role}.md"
        
        if not template_path.exists():
            logger.warning(f"提示词模板不存在: {template_path}，使用默认模板")
            return self._get_default_template(role)
        
        try:
            with open(template_path, 'r', encoding='utf-8') as f:
                template = f.read()
            
            # 缓存模板
            self.template_cache[cache_key] = template
            logger.debug(f"已加载提示词模板: {role} ({self.prompt_set})")
            return template
        except Exception as e:
            logger.error(f"加载提示词模板失败: {e}")
            return self._get_default_template(role)
    
    def render_template(
        self,
        role: str,
        context: Dict[str, Any],
        safe_mode: bool = True
    ) -> str:
        """
        渲染提示词模板（替换占位符）
        
        Args:
            role: 角色名称
            context: 上下文字典（占位符值）
            safe_mode: 安全模式（仅允许预定义占位符）
            
        Returns:
            渲染后的提示词
        """
        template = self.load_template(role)
        
        # 定义允许的占位符（白名单）
        allowed_placeholders = {
            'outline', 'count', 'genre', 'facts', 'style_guide',
            'episode_index', 'outline_plan', 'revision', 'description',
            'beats', 'characters', 'target', 'content', 'project',
            'rough_outline', 'target_episodes', 'outline_content',
            'total_episodes', 'detailed_outline', 'act_phase',
            'target_duration', 'is_first_episode', 'first_episode_minutes',
            'chapters', 'novel_text', 'target_minutes', 'min_seconds', 'max_seconds',
            'task', 'chapter_plan', 'character_details', 'chapter_range',
            'revision_suggestions', 'revision_issues'
        }
        
        # 准备上下文（填充缺失值为空字符串）
        render_context = {}
        for key in allowed_placeholders:
            value = context.get(key, '')
            # 转换为字符串
            if isinstance(value, (list, dict)):
                import json
                value = json.dumps(value, ensure_ascii=False, indent=2)
            elif value is None:
                value = ''
            render_context[key] = str(value)
        
        # 替换占位符
        try:
            # 使用正则表达式查找所有 {placeholder} 格式的占位符
            def replace_placeholder(match):
                placeholder = match.group(1)
                if safe_mode and placeholder not in allowed_placeholders:
                    logger.warning(f"未知占位符: {placeholder}，已跳过")
                    return match.group(0)  # 保持原样
                return render_context.get(placeholder, '')
            
            rendered = re.sub(r'\{(\w+)\}', replace_placeholder, template)
            return rendered
        except Exception as e:
            logger.error(f"渲染提示词模板失败: {e}")
            return template
    
    def _get_default_template(self, role: str) -> str:
        """
        获取默认提示词模板（后备方案）
        
        Args:
            role: 角色名称
            
        Returns:
            默认提示词字符串
        """
        default_templates = {
            "planner": """你是策划师，负责从题材与爽点抽取主题、节奏曲线与季/集配额。

项目大纲：{outline}
集数目标：{count}

请输出JSON格式：{{"seasonThemes": [], "pacingCurve": {{}}, "episodeQuota": number}}""",
            
            "outliner": """你是大纲师，负责生成分季/分集骨架（beats），对齐爽点与反转节奏。

剧集序号：{episode_index}
项目大纲：{outline}

请输出JSON格式：{{"episodeIndex": number, "beats": [{{"type": "setup|climax|twist|payoff", "hook": "", "durationHint": number}}]}}""",
            
            "character_designer": """你是角色设计师，负责输出人物卡与关系网。

人物描述：{description}

请输出JSON格式：{{"name": "", "bio": "", "traits": [], "goals": [], "conflicts": [], "visualRefs": []}}""",
            
            "scriptwriter": """你是剧本作者，负责按集生成剧本摘要与场景要素（可转分镜）。

剧集节拍：{beats}

请输出JSON格式：[{{"sceneIndex": number, "summary": "", "elements": [], "dialogue": "", "durationHint": number}}]""",
            
            "editor": """你是编辑与稽核，负责一致性检查、冲突检测与可改编性评审（视频友好）。

评审目标：{target}
待评审内容：{content}

请输出JSON格式：{{"target": "outliner|scriptwriter", "issues": [], "suggestions": [], "decision": "approve|revise"}}""",
            
            "outline_expander": """你是专业的短剧大纲师，负责将粗粒度大纲（题材、卖点）扩展为详细的故事大纲。

粗粒度大纲：
{rough_outline}

目标集数：{target_episodes}

请输出JSON格式：{{"title": "", "genre": [], "sellingPoints": [], "background": "", "characters": [], "mainPlot": "", "keyConflicts": [], "turningPoints": [], "pacing": "", "style": "", "targetAudience": ""}}"""
        }
        
        return default_templates.get(role, "你是一个AI助手。")
    
    def clear_cache(self):
        """
        清空模板缓存
        
        清除所有已加载的提示词模板缓存，下次使用时会重新加载
        """
        self.template_cache.clear()
        logger.debug("提示词模板缓存已清空")


# 全局加载器实例
_loader_instance: Optional[PromptTemplateLoader] = None


def get_prompt_loader(
    prompts_dir: str = "./prompts",
    prompt_set: str = "default"
) -> PromptTemplateLoader:
    """
    获取提示词模板加载器（单例）
    
    Args:
        prompts_dir: 提示词目录
        prompt_set: 提示词集名称
        
    Returns:
        PromptTemplateLoader实例
    """
    global _loader_instance
    if _loader_instance is None:
        _loader_instance = PromptTemplateLoader(prompts_dir, prompt_set)
    return _loader_instance


def load_prompt(
    role: str,
    context: Dict[str, Any],
    prompts_dir: str = "./prompts",
    prompt_set: str = "default"
) -> str:
    """
    快捷函数：加载并渲染提示词
    
    Args:
        role: 角色名称
        context: 上下文字典
        prompts_dir: 提示词目录
        prompt_set: 提示词集名称
        
    Returns:
        渲染后的提示词
    """
    loader = get_prompt_loader(prompts_dir, prompt_set)
    return loader.render_template(role, context)

